﻿using System;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Newtonsoft.Json;
using DbToPbiSvc.Logging;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace DbToPbiSvc.PowerBi
{

    public class Helper
    {

        /// <summary>
        /// Get access token:
        /// To call a Power BI REST operation, create an instance of AuthenticationContext and call AcquireToken
        /// AuthenticationContext is part of the Active Directory Authentication Library NuGet package
        /// To install the Active Directory Authentication Library NuGet package in Visual Studio,
        /// run "Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory" from the nuget Package Manager Console.
        /// </summary>
        /// <param name="clientId"></param>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <param name="refreshToken"></param>
        /// <returns></returns>
        public static string GetAccessToken(string clientId, string username, string password, ref string refreshToken)
        {

            string token = string.Empty;

            try
            {

                LogHelper.TraceDebugInfo("IN");

                string authorityUri = "https://login.windows.net/common/oauth2/authorize";
                AuthenticationContext authContext = new AuthenticationContext(authorityUri);

                if (string.IsNullOrEmpty(refreshToken))
                {
                    string resourceUri = "https://analysis.windows.net/powerbi/api";

                    UserCredential user = new UserCredential(username, password);

                    AuthenticationResult authResult = authContext.AcquireToken(resourceUri, clientId, user);

                    token = authResult.AccessToken;
                    refreshToken = authResult.RefreshToken;
                }
                else
                {
                    token = authContext.AcquireTokenByRefreshToken(refreshToken, clientId).AccessToken;
                }

            }
            catch (Exception exc)
            {
                LogHelper.TraceError(exc);
            }
            finally
            {
                LogHelper.TraceDebugInfo("OUT");
            }

            return token;

        }

        private static async Task<string> CallApi(string token, string endpoint, CallType callType, string payload)
        {

            string returnValue = string.Empty;
            HttpClient client = null;

            try
            {

                LogHelper.TraceDebugInfo("IN");

                client = new HttpClient();
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                HttpResponseMessage response = null;

                switch (callType)
                {

                    case CallType.Post:

                        HttpContent httpContent = null;

                        if (payload != null)
                        {
                            httpContent = new StringContent(payload, Encoding.UTF8, "application/json");
                        }

                        response = await client.PostAsync(endpoint, httpContent);

                        break;
                
                    case CallType.Get:

                        response = await client.GetAsync(endpoint);

                        break;

                    case CallType.Delete:

                        response = await client.DeleteAsync(endpoint);

                        break;

                }

                if (response != null)
                {
                    returnValue = await response.Content.ReadAsStringAsync();
                }

            }
            catch (Exception exc)
            {
                LogHelper.TraceError(exc);
            }
            finally
            {
                client?.Dispose();

                LogHelper.TraceDebugInfo("OUT");
            }

            return returnValue;
        }

        public static async Task EmptyDataset(string token, string datasetId, string tableName)
        {
            try
            {
                LogHelper.TraceDebugInfo("IN");

                string payload = $"https://api.powerbi.com/v1.0/myorg/datasets/{datasetId}/tables/{tableName}/Rows";

                await CallApi(token, payload, CallType.Delete, null);
            }
            catch (Exception exc)
            {
                LogHelper.TraceError(exc);
            }
            finally
            {
                LogHelper.TraceDebugInfo("OUT");
            }
        }

        public static async Task AddRows(string token, string datasetId, string tableName, string content)
        {
            try
            {
                LogHelper.TraceDebugInfo("IN");

                string payload = $"https://api.powerbi.com/v1.0/myorg/datasets/{datasetId}/tables/{tableName}/Rows";

                await CallApi(token, payload, CallType.Post, string.Concat("{\"rows\": ", content, "}"));
            }
            catch (Exception exc)
            {
                LogHelper.TraceError(exc);
            }
            finally
            {
                LogHelper.TraceDebugInfo("OUT");
            }
        }

        public static async Task CreateDataset(string token, string tableDefinition)
        {

            try
            {
                LogHelper.TraceDebugInfo("IN");

                string payload = "https://api.powerbi.com/v1.0/myorg/datasets";

                await CallApi(token, payload, CallType.Post, tableDefinition);
            }
            catch (Exception exc)
            {
                LogHelper.TraceError(exc);
            }
            finally
            {
                LogHelper.TraceDebugInfo("OUT");
            }

        }

        public static async Task<PbiDatasets> GetDatasets(string token)
        {

            PbiDatasets datasets = null;

            try
            {
                LogHelper.TraceDebugInfo("IN");

                string payload = "https://api.powerbi.com/v1.0/myorg/datasets";

                string response = await CallApi(token, payload, CallType.Get, null);

                datasets = (PbiDatasets)JsonConvert.DeserializeObject(response, typeof(PbiDatasets));
            }
            catch (Exception exc)
            {
                LogHelper.TraceError(exc);
            }
            finally
            {
                LogHelper.TraceDebugInfo("OUT");
            }

            return datasets;

        }

    }

    public class PbiDatasets
    {
        public PbiDataset[] Value { get; set; }
    }

    public class PbiDataset
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }

    public enum CallType
    {
        Get,
        Post,
        Delete
    }

}
